Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add remote pinning to ipfs command #7661

Merged
merged 128 commits into from
Dec 9, 2020
Merged

add remote pinning to ipfs command #7661

merged 128 commits into from
Dec 9, 2020

Conversation

petar
Copy link
Contributor

@petar petar commented Sep 8, 2020

@Jorropo

This comment has been minimized.

@petar petar requested a review from aschmahmann September 11, 2020 15:24
.circleci/config.yml Outdated Show resolved Hide resolved
Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for starting this. Quick feedback:

.circleci/config.yml Outdated Show resolved Hide resolved
core/commands/remotepin.go Outdated Show resolved Hide resolved
core/commands/remotepin.go Outdated Show resolved Hide resolved
lidel added a commit to ipfs/js-ipfs that referenced this pull request Sep 18, 2020
This adds basic boilerplate for supporting remote pinning commands
introduced in ipfs/kubo#7661

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
@aschmahmann aschmahmann mentioned this pull request Sep 30, 2020
73 tasks
@lidel
Copy link
Member

lidel commented Oct 6, 2020

@petar is the API under /api/v0/pin/remote/* stable enough to start implementation in js-ipfs-http-client (ipfs/js-ipfs#3293) in parallel to this PR?

cc @Gozala @rafaelramalho19

@petar
Copy link
Contributor Author

petar commented Oct 6, 2020

@petar is the API under /api/v0/pin/remote/* stable enough to start implementation in js-ipfs-http-client (ipfs/js-ipfs#3293) in parallel to this PR?

cc @Gozala @rafaelramalho19

@lidel Yes. The additional API for configuring remote services "/pin/remote/service" hasn't been reviewed by others carefully yet. Feel free to criticize it if you get to it. It meets @aschmahmann 's considerations, I believe.

@aschmahmann
Copy link
Contributor

@lidel I haven't had a chance to look at the pin remote service API yet, but will take a look later today.

The rest of the pin remote API should be reasonably stable, although our call on Friday is designed to give that a second pass to make sure we're happy with how it looks and don't want to rename and commands, arguments or options. I suspect any changes that come out of that meeting will be fairly cosmetic though.

core/commands/remotepin.go Outdated Show resolved Hide resolved
@lidel
Copy link
Member

lidel commented Dec 4, 2020

@Gozala thanks for feedback! Quick thoughts:

  • pushing requestID to options in JS sgtm. but I think that does not impact this PR and will be scoped to feat: support remote pinning services in ipfs-http-client js-ipfs#3293?
    (if so, we should move JS-specific design decisions to that PR)

  • Is there reason why name can't be an array of possible matches?

    No strong reason, mostly to keep MVP simple and aligned with upstream API:

    • it is not an array in Pinning Service API, so would require multiple requests here
    • we support comma-separated notation --cid=Qm1,Qm2, in case of name it would not be possible, or would break for names that include ,
  • It is also kind of odd that you can ls / rm by requestID + the other options

    When requestID is passed, direct lookup is performed and due to this options are ignored (otherwise we would have to duplicate work and implement filtering in the client).
    @aschmahmann Perhaps the fix here is to return an error when both requestID and query filters are passed, informing user that its either one or another?

  • is there good reason to expose a requestId to the user ?

    To make --background=true work and be able to check ongoing pinning status later.
    If you have an idea how we can deliver that without exposing "PinID" (aka "RequestID") this is a good time to write it down.

@Gozala
Copy link

Gozala commented Dec 4, 2020

  • pushing requestID to options in JS sgtm. but I think that does not impact this PR and will be scoped to ipfs/js-ipfs#3293?
    (if so, we should move JS-specific design decisions to that PR)

Well problem is that it would also affect JS CLI which in turn would be bound to the implementation or will have to take a more custom approach

@Gozala
Copy link

Gozala commented Dec 4, 2020

  • When requestID is passed, direct lookup is performed and due to this options are ignored (otherwise we would have to duplicate work and implement filtering in the client).
    @aschmahmann Perhaps the fix here is to return an error when both requestID and query filters are passed, informing user that its either one or another?

Sounds to me that maybe it should be a stat command instead

@aschmahmann
Copy link
Contributor

Well problem is that it would also affect JS CLI which in turn would be bound to the implementation or will have to take a more custom approach

I thought JS didn't have as strong coupling between the CLI and HTTP API as Go did, am I misunderstanding? Fundamentally Go, JS, and Bash all have different each have their own semantics about what's preferred so moving around some things on the interface in JS seems reasonable unless it's a big pain. For example, what happens when we want to extend the number of services to be 1 or more? That's not easily implemented via just a ? in JS anyway.

@aschmahmann Perhaps the fix here is to return an error when both requestID and query filters are passed, informing user that its either one or another?

🤷 I think both options are acceptable. I'm pretty sure we discussed this and @Gozala's suggestion

Sounds to me that maybe it should be a stat command instead

but decided not to since we might want stat for something else and we already have some user expectations via ipfs pin ls <ipfs-path> which is somewhat similar in design.

@lidel
Copy link
Member

lidel commented Dec 4, 2020

While discussing issues raised by @Gozala we took a quick step back and looked at pin remote and potential use of requestid.

Below are quick notes from our call, so we have our rationale documented.

With requestid 💫🤔

pin remote rm | ls is confusing because it operates in two modes:

  • direct requestid match (which ignores filters like cid,name and status)
  • search query (returns matches for passed filters: cid,name and status)

Potential fixes:

  1. extract "direct match" to separate pin remote stat <requestid>
    • pro: follows existing convention of dag stat and files stat
    • con: does not solve pin remote rm <requestid> --name=foo
  2. return error when both requestid and filters are provided
    • pro: easy and quick fix that works for both ls and rm
    • con: ? (we still have overcomplicated api)

Without requestid 💚

What if we make requestid an internal implementation detail and remove it from pin remote command outputs and filters? (at least for MVP)

pin remote rm | ls already demonstrate we can live without it by accepting search filters such as --cid= and --name

  • pros:
    • lower cognitive overhead: pin remote API does not import and expose any third-party opaque identifiers into our api
    • api is simpler and easier to backport to pin local
    • does not lock us into decisions made for (somehow provisional) Pinning Services API
  • cons:
    • requires a small refactor (mostly removal of code)

Q&A

Q: how to differentiate between two pins for the same cid
A: use different name

Q: what if unique name is not provided?
A: (now - MVP) just create duplicate (all duplicates can be removed with pin remote rm --cid -f)
A: (idea) we could improve ergonomics by checking for cid+name duplicates, and reuse existing one (this implies cid+name as the de facto unique index for both local and remote pinning - feasibility TBD)

Decision

Remove requestid (and other unused fields) from API output for now.

lidel added 2 commits December 4, 2020 22:18
Rationale:
#7661 (comment)

Note: one config test fails due to unrelated changes,
this will be addressed separatelly.
We will replace this with smarter logic in separate PR
with MFSRepinInterval
@Gozala
Copy link

Gozala commented Dec 4, 2020

One more thing I've noticed with ipfs pin remote service ls:

ipfs pin remote service ls --pin-count 
mock http://localhost:8080 1/0/0/0
test http://localhost:8080 offline

Same call over the HTTP endpoint

curl -X POST 'http://127.0.0.1:5002/api/v0/pin/remote/service/ls?pin-count=true'
{
  "RemoteServices": [
    {
      "Service": "mock",
      "ApiEndpoint": "http://localhost:8080",
      "PinCount": {
        "Queued": 1,
        "Pinning": 0,
        "Pinned": 0,
        "Failed": 0
      }
    },
    {
      "Service": "test",
      "ApiEndpoint": "http://localhost:8080"
    }
  ]
}

Note that in CLI one can tell that service is not reachable, while over HTTP only clue is lack of PinCount. I was wondering maybe we could do better here by renaming --pin-count to --stat and turn the output of HTTP response to following instead:

curl -X POST 'http://127.0.0.1:5002/api/v0/pin/remote/service/ls?stat=true'
{
  "RemoteServices": [
    {
      "Service": "mock",
      "ApiEndpoint": "http://localhost:8080",
      "Stat": {
        "Status": "Online",
        "PinCount": {
          "Queued": 1,
          "Pinning": 0,
          "Pinned": 0,
          "Failed": 0
        }
      }
    },
    {
      "Service": "test",
      "ApiEndpoint": "http://localhost:8080"
      "Stat": {
        "Status": "Offline"
       }
    }
  ]
}

@Gozala
Copy link

Gozala commented Dec 4, 2020

Oh and also "online" | "offline" may no be a good working here, maybe "available" | "unavailable" or "reachable" | "unreachable" might be a better way to talk about it. Because node may be offline instead of service or maybe service is unreachable because of network fragmentation.

@lidel
Copy link
Member

lidel commented Dec 4, 2020

@Gozala good feedback, thanks!
Applied your suggestions (went with shorter statuses: valid|invalid|unknown for now)

Without --stat all services are in unknown state:

{
  "RemoteServices": [
    {
      "Service": "test-valid",
      "ApiEndpoint": "https://testapi1.example.com/psa",
      "Stat": {
        "Status": "unknown"
      }
    },
    {
      "Service": "test-invalid",
      "ApiEndpoint": "https://testapi2.example.com/psa",
      "Stat": {
        "Status": "unknown"
      }
    }
  ]
}

With --stat we see valid and invalid ones:

{
  "RemoteServices": [
    {
      "Service": "test-valid",
      "ApiEndpoint": "https://testapi1.example.com/psa",
      "Stat": {
        "Status": "valid",
        "PinCount": {
          "Queued": 0,
          "Pinning": 0,
          "Pinned": 2,
          "Failed": 0
        }
      }
    },
    {
      "Service": "test-invalid",
      "ApiEndpoint": "https://testapi2.example.com/psa",
      "Stat": {
        "Status": "invalid"
      }
    }
  ]
}

@Gozala
Copy link

Gozala commented Dec 5, 2020

Thanks @lidel! Do you think it would make sense to only include Stat field if --stat isn't passed ?

@lidel
Copy link
Member

lidel commented Dec 5, 2020

@Gozala sgtm – changed in 32f8950 (#7661):

Without --stat :

{
  "RemoteServices": [
    {
      "Service": "test-valid",
      "ApiEndpoint": "https://testapi1.example.com/psa"
    },
    {
      "Service": "test-invalid",
      "ApiEndpoint": "https://testapi2.example.com/psa"
    }
  ]
}

@aschmahmann aschmahmann merged commit a8c7980 into master Dec 9, 2020
dennis-tra pushed a commit to dennis-tra/go-ipfs that referenced this pull request Dec 13, 2020
Added support for remote pinning services

A pinning service is a service that accepts CIDs from a user in order to host the data associated with them.
The spec for these services is defined at https://github.com/ipfs/pinning-services-api-spec

Support is available via the `ipfs pin remote` CLI and the corresponding HTTP API

Co-authored-by: Petar Maymounkov <petarm@gmail.com>
Co-authored-by: Marcin Rataj <lidel@lidel.org>
Co-authored-by: Adin Schmahmann <adin.schmahmann@gmail.com>
@lidel lidel deleted the petar/pincli branch January 26, 2021 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants